using System;
using System.Collections.Generic;
using Nvigorate.Relational.Record;
using Nvigorate.Relational.State;

namespace Nvigorate.Relational.Mapping.Interface
{
    public interface IBindingMap
    {
        /// <summary>
        /// Gets or sets a value indicating whether the delete operation is available 
        /// for the mapped type.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can delete; otherwise, <c>false</c>.
        /// </value>
        bool CanDelete
        { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether insert operation is available 
        /// for the mapped type.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can insert; otherwise, <c>false</c>.
        /// </value>
        bool CanInsert
        { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the select operation is available 
        /// for the mapped type.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can select; otherwise, <c>false</c>.
        /// </value>
        bool CanSelect
        { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the update operation is available 
        /// for the mapped type.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance can update; otherwise, <c>false</c>.
        /// </value>
        bool CanUpdate 
        { get; set; }

        /// <summary>
        /// In inheritence scenarios where the type returned from the database
        /// is determinate upon the results retrieved, the discriminator
        /// provides the decision criteria for determining which type
        /// should be created on a per record basis
        /// </summary>
        IDiscriminate Discriminator { get; set; }

        /// <summary>
        /// The types which this map inherits the map from
        /// </summary>
        IList<Type> Inherits 
        { get; set; }

        /// <summary>
        /// Provides a list of types which inherit from this map
        /// </summary>
        IList<Type> InheritedBy 
        { get; set; }

        /// <summary>
        /// The name of the source which this map relates to
        /// </summary>
        string RepositoryName
        { get; set; }

        /// <summary>
        /// The name of the target entity
        /// </summary>
        string TargetName
        { get; set; }

        /// <summary>
        /// The type of the target entity
        /// </summary>
        Type TargetType
        { get; set; }

        /// <summary>
        /// A list of relationships between this mapped type and others
        /// </summary>
        List<ITargetRelationship> Relationships 
        { get; set; }

        /// <summary>
        /// The sources that combine to populate the target
        /// </summary>
        Dictionary<string, ISourceMap> Sources
        { get; set; }

        /// <summary>
        /// Adds an assignment to an existing SourceMap
        /// </summary>
        /// <param name="assignment">The assignment to add</param>
        void AddAssignment(IAssignment assignment);

        /// <summary>
        /// Allow adding a source map to the binding definition
        /// </summary>
        /// <param name="map"></param>
        void AddSource(ISourceMap map);

        /// <summary>
        /// Retrieve all assignments in the map
        /// </summary>
        /// <returns>A list of all assignments</returns>
        IEnumerable<IAssignment> GetAssignments();

        /// <summary>
        /// Retrieve a list of assignments across all sources which match the predicate
        /// </summary>
        /// <param name="predicate">The predicate to search by</param>
        /// <returns>A list of assignments across all sources which match the predicate</returns>
        IEnumerable<IAssignment> GetAssignmentsByPredicate(Func<IAssignment, bool> predicate);

        /// <summary>
        /// Get the assignment for the source field
        /// </summary>
        /// <param name="source"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        IAssignment GetAssignmentBySourceField(string source, string field);

        /// <summary>
        /// Get the assignment for the target field (given the source name)
        /// </summary>
        /// <param name="source"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        IAssignment GetAssignmentByTargetField(string source, string field);

        /// <summary>
        /// Get the assignments for the target field
        /// </summary>
        /// <param name="field"></param>
        /// <returns></returns>
        IEnumerable<IAssignment> GetAssignmentsByTargetField(string field);

        /// <summary>
        /// Returns child source maps
        /// </summary>
        /// <returns>Returns all maps for the type except the root</returns>
        IEnumerable<ISourceMap> GetChildSources();

        /// <summary>
        /// Returns child source maps
        /// </summary>
        /// <returns>Returns all child maps of the parent map for the type</returns>
        IEnumerable<ISourceMap> GetChildSources(string parentSourceName);

        /// <summary>
        /// Gets the child types which inherit their map from this one
        /// </summary>
        /// <returns>The child types which inherit from this</returns>
        IEnumerable<Type> GetChildTypes();

        /// <summary>
        /// Find a relationship to the related type for this mapped type
        /// </summary>
        /// <param name="relatedType">The subject or relative type</param>
        /// <returns>The relationship which ties this mapped type to the relatedType</returns>
        T GetRelationshipForType<T>(Type relatedType) where T : ITargetRelationship;

        /// <summary>
        /// Retrieves the name of the root source
        /// </summary>
        /// <returns></returns>
        string GetRootName();

        /// <summary>
        /// Retrieves the root source map
        /// </summary>
        /// <returns></returns>
        ISourceMap GetRoot();

        /// <summary>
        /// Returns a list of assignments provided by the source record
        /// </summary>
        /// <param name="sourceRecord">The record containing values for assignment points</param>
        /// <returns>A list of assignments provided by the source record</returns>
        IEnumerable<IAssignment> GetSuppliedAssignments(IRecord sourceRecord);

        /// <summary>
        /// Gets the source maps in create order
        /// </summary>
        /// <returns>The source maps in create order</returns>
        IEnumerable<ISourceMap> GetSourceMapsInCreateOrder(bool reverse);

        /// <summary>
        /// Marks which sources were included in populating the instance
        /// </summary>
        /// <param name="state">The state information to update</param>
        void MarkPersistedSources(IPersistenceState state);

        /// <summary>
        /// Marks which properties on the instance are considered party of the identifying key
        /// </summary>
        /// <param name="state">The state information to update</param>
        void MarkTargetKeys(IPersistenceState state);

        /// <summary>
        /// Merges a parent map into this one
        /// </summary>
        /// <param name="parentMap"></param>
        void Merge(IBindingMap parentMap);
    }
}